package core;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import projectiles.Projectile;
import superweapons.NukePlane;
import superweapons.SuperWeapon;
import towers.Tower;
import enemies.Enemy;

/**
 * @author Arno de Jager
 *
 */
public class View extends JPanel implements Observer {
	
	private Model model;
	private ViewMenu east;
	private NextWavePanel waveInfo;
	private MapEditorStatusPanel mapEditorStatusPanel;
	private Mouse mouse;
	private MapEditorMenu mapEditorMenu;
	private Controller controller;
	
	private static final ImageIcon infantryIcon = new ImageIcon( View.class.getResource( "../images/infantry.gif"));
	private static final ImageIcon jeepIcon = new ImageIcon( View.class.getResource( "../images/jeep.gif"));
	private static final ImageIcon tankIcon = new ImageIcon( View.class.getResource( "../images/tank.gif"));
	
	private static final ImageIcon pauzeIcon = new ImageIcon(View.class.getResource("../images/pause.gif"));
	private static final ImageIcon baseIcon = new ImageIcon( View.class.getResource("../images/buttons/base.gif") );
	private static final ImageIcon roadIcon = new ImageIcon( View.class.getResource("../images/buttons/weg.gif") );
	private static final ImageIcon undoIcon = new ImageIcon( View.class.getResource("../images/buttons/undo.gif") );
	
	private static final ImageIcon startButton = new ImageIcon( View.class.getResource("../images/buttons/start.gif") );
	
	private BufferedImage bufferedBattlefield = new BufferedImage(Model.battlefieldWidth, Model.battlefieldHeight, BufferedImage.TYPE_INT_RGB);
	
	private JLabel mapeditorStatus = new JLabel();

	public View( Model m, Controller c )
	{
		this.model = m;
		this.controller = c;
		
		create();
	}
	
	private void create()
	{
		JPanel center = new JPanel(new BorderLayout());
		JPanel battlefield = new BattlefieldView();
		mouse = controller.getMouse();
		battlefield.addMouseListener( mouse );
		battlefield.addMouseMotionListener(mouse);
		
		// Bepaling van layout
		this.setLayout(new BorderLayout());
		add(center, BorderLayout.CENTER);
		center.add(battlefield, BorderLayout.CENTER);
		
		if ( model.isMapEditor() )
		{
			mapEditorMenu = new MapEditorMenu();
			mapEditorStatusPanel = new MapEditorStatusPanel();
			add(mapEditorMenu, BorderLayout.EAST);
			
			center.add(mapEditorStatusPanel, BorderLayout.SOUTH);
		}
		else
		{
			waveInfo = new NextWavePanel();
			east = new ViewMenu(model, controller);
			add(east, BorderLayout.EAST);
			
			center.add(waveInfo, BorderLayout.SOUTH);
		}
	}
	
	public void reset()
	{
		removeAll();
		create();
	}
	
	public void update(Observable o, Object arg ) {
		
		if ( arg.equals("reset"))
		{
			reset();
			return;
		}
		
		if( model.isMapEditor() )
			mapEditorStatusPanel.update(o, arg);
			
		// Update ook menu
		if ( arg.equals("updateStats"))
			east.update(o, arg);
		
		// Er is iets veranderd, repaint alles!
		else if ( arg.equals("repaint"))
			repaint();
		
		// Next wave info moet aangepast worden
		else if ( !model.isMapEditor() && arg.equals("nextwave"))
			waveInfo.update(o, arg);
		
		else if (arg.equals("highscore"))
			showHighScore();
	}
	
	public void showHighScore(){
		String[][] arr = model.getStats().getHighScore();
		
		StringBuffer s = new StringBuffer();
		for( int i = 0; i < arr.length; i++ ){
			if ( arr[i][0] != null ) {
				s.append( arr[i][0] + " \t" );
				s.append( arr[i][1] + " \t" );
				s.append( "\n" );
			}
		}
		
		JOptionPane.showMessageDialog(this, "Highscore\nName Score\n" + s.toString() );
	
	}
	
	
	class BattlefieldView extends JPanel {
		
		public void paintComponent(Graphics graphics) {
			Graphics2D g = (Graphics2D)bufferedBattlefield.getGraphics();
			g.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
			
			//Eerst de map zodat deze niet bovenop staat
			model.getMap().draw(g, this.getBounds(), this);
			
			if ( !model.isMapEditor() )
			{
			
				//Als er een SuperweaponNuke is, teken hem nu
				for(SuperWeapon sw : model.getSuperWeapons()){
					if(sw instanceof NukePlane){
						NukePlane swn = (NukePlane) sw;
						if(swn.getNuke() != null){
							swn.getNuke().draw(g, this.getBounds(), this);
						}
					}
				}
				
				//Dan de torens zodat de projectielen niet 'onder' de toren door vliegen
				for(Tower t : model.getTowers()) {
					t.draw(g, this.getBounds(), this);
				}
				
				//En de enemys om dezelfde reden
				for(Enemy e : model.getEnemies()) {
					e.draw(g, this.getBounds(), this);
				}
				
				// Projectielen moeten over enemies en towers getekend worden
				for(Projectile p : model.getProjectiles()) {
					p.draw(g, this.getBounds(), this);
				}
				
				g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
				for(Explosion ex : model.getExplosions()) {
					ex.draw(g, this.getBounds(), this);
				}
				
				for(SuperWeapon sw : model.getSuperWeapons()){
					sw.draw(g, this.getBounds(), this);
				}
				
				// Eventueel pause-icon
				if ( !model.hasEnded() && model.isPaused() )
					g.drawImage( pauzeIcon.getImage(), 5, 5, this );
				
				//mouse actie tekenen
				//controleren op nieuw geselecteerde tower
				if( mouse.getSelectedItem() != null && mouse.getSelectedItem().position == null){
					Point point = mouse.getMouseDot();
					//controleren of plek bezet is, en kleur toekennen
					if(model.placeOccupied( point, mouse.getSelectedItem() )){
							g.setColor( Color.RED );
					}else{
							g.setColor( Color.GREEN );
					}
					//we moeten nu schaduw tekenen op veld
					g.drawRect(point.x-mouse.getSelectedItem().image.getIconHeight()/2, point.y-mouse.getSelectedItem().image.getIconWidth()/2, mouse.getSelectedItem().image.getIconWidth(), mouse.getSelectedItem().image.getIconHeight());
				}else if(mouse.getSelectedItem() != null && mouse.getSelectedItem().position != null){
					//er is een bestaande tower geselecteerd, vierkant eromheen tekenen.
					Point2D.Double point = mouse.getSelectedItem().position;
					g.setColor( Color.WHITE );
					g.drawRect( (int) point.getX()-3, (int) point.getY()-3, mouse.getSelectedItem().image.getIconWidth()+6, mouse.getSelectedItem().image.getIconHeight()+6);
	
				}
				
				//kijken of er een superwapen geselecteerd is
				if(mouse.getSelectedSuperWeapon() != null){
					//op veld een cirkel tekenen
					Dimension k = mouse.getSelectedSuperWeapon().getSize();
					Point point = mouse.getMouseDot();
					g.setColor(Color.ORANGE);
					g.drawOval((int)point.getX()-k.width/2, (int)point.getY()-k.height/2, k.width, k.height);
				}
	
				
				// basis health kleiner dan 0, spel afgelopen
				if ( model.getMap().getBase().getHealth() <= 0 ) {
					g.setFont( new Font("Arial", Font.PLAIN, 100));
					
					g.setColor( Color.black );
					g.drawString("YOU LOSE!", 105, 255);
					
					g.setColor( Color.white );
					g.drawString("YOU LOSE!", 100, 250);
				}
				else if ( model.hasEnded() && model.getStats().getWave() >= 100 ) {
					g.setFont( new Font("Arial", Font.PLAIN, 100));
					
					g.setColor( Color.black );
					g.drawString("YOU WIN!", 105, 255);
					
					g.setColor( Color.white );
					g.drawString("YOU WIN!", 100, 250);
				}
			}
			
			graphics.drawImage(bufferedBattlefield, 0, 0, null);
		}
	}
	
	class MapEditorStatusPanel extends JPanel implements Observer {
		public MapEditorStatusPanel()
		{
			setLayout( new GridLayout(1,2));
			setPreferredSize( new Dimension(Model.battlefieldWidth, 60) );
			setBackground( new Color(60, 79, 104) );
			
			JPanel p = new JPanel();
			p.setBackground( new Color(60, 79, 104) );
			p.setAlignmentX( JPanel.CENTER_ALIGNMENT );
			p.setBorder( new EmptyBorder(15, 15, 15, 15));
			
			mapeditorStatus = new JLabel("Kies een punt om de basis te plaatsen...");
			mapeditorStatus.setFont( new Font("Verdana", Font.PLAIN, 10) );
			mapeditorStatus.setForeground( Color.white );
			p.add( mapeditorStatus );
			
			add( p );
		}
		
		public void update(Observable o, Object arg ) {
			if( arg.equals("status klaar"))
				mapeditorStatus.setText("Kies een punt om te plaatsen...");
			
			else if( arg.equals("status nieuwe route"))
				mapeditorStatus.setText("De weg is geplaatst en de route is compleet. Kies een punt voor een nieuwe route");
			
			else if( arg.equals("status geen basis"))
				mapeditorStatus.setText("Plaats eerst een basis!");
			
			else if( arg.equals("status basis geplaatst"))
				mapeditorStatus.setText("Basis is geplaatst");
			
			else if ( arg.equals("status route eindigt niet in basis"))
				mapeditorStatus.setText("Kan spel niet starten: een van de routes eindigt niet in de basis!");
		}
	}
	
	class NextWavePanel extends JPanel implements Observer {
		WaveInfo left = new WaveInfo( false );
		WaveInfo right = new WaveInfo( true );
		
		public NextWavePanel() {
			setLayout( new GridLayout(1,2));
			setPreferredSize( new Dimension(Model.battlefieldWidth, 60) );
			setBackground( new Color(60, 79, 104) );
			
			SuperweaponButtons swb = new SuperweaponButtons(); 
			
			add( createPart( "Superweapons", swb));
			add( createPart( "Second Wave", left ) );
			add( createPart( "First Wave", right ) );
		}
		
		private JPanel createPart( String strTitle, JPanel content ) {
			JPanel title = new JPanel();
			title.setBackground( Color.black );
			
			JLabel titleLabel = new JLabel( strTitle );
			titleLabel.setForeground( Color.white );
			titleLabel.setFont( new Font("Verdana",Font.BOLD, 12) );
			title.add( titleLabel );
			
			JPanel x = new JPanel( new BorderLayout() );
			x.setBackground( new Color(60, 79, 104) );
			x.add( title, BorderLayout.NORTH );
			x.add( content, BorderLayout.CENTER  );
			
			return x;
		}

		public void update(Observable o, Object arg ) {
			left.update( o, arg );
			right.update( o, arg );
		}
		
		class SuperweaponButtons extends JPanel {
			public SuperweaponButtons() {
				setBackground( new Color(60, 79, 104) );
				for (SuperweaponController sc : Controller.main.getSuperweapons()) {
					add(sc.getButton());
				}
			}
		}
		
		class WaveInfo extends JPanel {
			private ImageIcon enemy = infantryIcon;
			private boolean firstWave;
			
			public WaveInfo( boolean firstWave ) {
				this.firstWave = firstWave;
				
				String waveType;
				
				if ( this.firstWave ) {
					waveType = model.getFirstWave();
				}
				else {
					waveType = model.getSecondWave();
				}
								
				if ( waveType.equals("Infantry") )
					enemy = infantryIcon;
				else if ( waveType.equals("Jeep") )
					enemy = jeepIcon;
				else if ( waveType.equals("Tank") )
					enemy = tankIcon;
			}
			
			public void paintComponent( Graphics g ) {
				// Aantal units
				g.setColor( Color.WHITE );
				g.setFont( new Font("Tahoma", Font.BOLD, 12) );
				
				int level = model.getStats().getWave() + 1;
				if ( !this.firstWave )
					level++;
				
				int aantalEnemies = model.getCountEnemies( level );
				g.drawString( aantalEnemies + " unit" + (aantalEnemies == 1 ? "" : "s"), 90, 20);
				
				// 3 plaatjes van type vijand
				int x = 170;
				
				Graphics2D g2d = (Graphics2D)g;
			    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

			    AffineTransform oldForm = g2d.getTransform();
			    AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();
			    
			    newForm.rotate(Math.toRadians(90), x , 7);
			    
			    g2d.setTransform(newForm);
				g2d.drawImage( enemy.getImage(), x, 0, this );
				g2d.setTransform(oldForm);
			}
			
			public void update(Observable o, Object arg ) {
				String waveType;
				
				if ( this.firstWave ) {
					waveType = model.getFirstWave();
				}
				else {
					waveType = model.getSecondWave();
				}
				
				if ( waveType.equals("Infantry") )
					enemy = infantryIcon;
				else if ( waveType.equals("Jeep") )
					enemy = jeepIcon;
				else if ( waveType.equals("Tank") )
					enemy = tankIcon;
			}
		}
	}
	
	class MapEditorMenu extends JPanel
	{
		private Color backgroundColor = new Color(60, 79, 104);
		public MapEditorMenu()
		{
			this.setLayout( new BorderLayout() );
			this.setPreferredSize( new Dimension(210, 485));
			this.setBackground( backgroundColor );
			
			JPanel p = new JPanel( new GridLayout(2,1) );
			p.setBackground( backgroundColor );
			
			JLabel tekst = new JLabel("<html>Welkom bij de mapeditor<br>Je kan hier je eigen maps maken<br><br>Kies een van de bovenste 2 buttons om deze te plaatsen.<br><br>Een weg is \"klaar\" als deze eindigt in de basis. Meerdere routes zijn mogelijk<br><br>Klik op 'undo' om laatste punt van de weg te verwijderen</html>");
			tekst.setVerticalAlignment(JLabel.TOP);
			tekst.setHorizontalAlignment(JLabel.CENTER);
			tekst.setBorder( new EmptyBorder(15, 15, 15, 5) );
			tekst.setFont(new Font("Verdana", Font.PLAIN, 11) );
			tekst.setForeground( Color.white );
			p.add( tekst );
			
			JPanel p2 = new JPanel( new GridLayout(2,2) );
			p2.setBackground( backgroundColor );
			p2.add( new ImgButton("road", roadIcon, "Weg") );
			p2.add( new ImgButton("base", baseIcon, "Basis") );
			p2.add( new ImgButton("undo", undoIcon, "Undo") );
			p.add(p2);
			
			add(p, BorderLayout.CENTER);
			
			add( new MenuButton("start", startButton, controller), BorderLayout.SOUTH);
		}
		
		class ImgButton extends JButton {
			private ImgButton( String action, ImageIcon img, String naam ) {
				this.addActionListener( controller );
				this.setIcon( img );
				this.setActionCommand( action );
				this.setSize( new Dimension(50, 50) );
				this.setBackground( new Color(255, 14, 16) );
				this.setForeground( Color.WHITE );
				this.setContentAreaFilled(false);
				this.setBorder(BorderFactory.createEmptyBorder());
				this.setPreferredSize( new Dimension(50, 50) );
				this.setText(naam);
			}
		}
		
	}
	
	// Brede ronde rode button
	class MenuButton extends JButton {
		private MenuButton( String action, ImageIcon img, Controller c ) {
			this.addActionListener( c );
			this.setIcon( img );
			this.setActionCommand( action );
			this.setSize( new Dimension(200, 18) );
			this.setBackground( new Color(255, 14, 16) );
			this.setForeground( Color.WHITE );
			this.setContentAreaFilled(false);
			this.setBorder(BorderFactory.createEmptyBorder());
			this.setPreferredSize( new Dimension(200, 25) );
			this.setFocusable( false );
		}
	}
}
